#include <cstdio>

#include "btBulletDynamicsCommon.h"
#include "BulletSoftBody/btSoftRigidDynamicsWorld.h"
#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h"
#include "BulletSoftBody/btSoftBodyHelpers.h"
#include "BulletCollision/CollisionShapes/btBox2dShape.h"

#ifdef _WIN32
#include "GLDebugFont.h"
#include "GLDebugDrawer.h"
#include "GlutStuff.h"
#include "GL_ShapeDrawer.h"
#else
#include "GL/GLDebugFont.h"
#include "GL/GLDebugDrawer.h"
#include "GL/GlutStuff.h"
#include "GL/GL_ShapeDrawer.h"
#endif //_WINDOWS

#include "AngryBr3ds.h"

#ifndef M_PI
#define M_PI       3.14159265358979323846
#endif

#ifndef M_PI_2
#define M_PI_2     1.57079632679489661923
#endif

#ifndef M_PI_4
#define M_PI_4     0.785398163397448309616
#endif

#ifndef DEGTORAD
#define DEGTORAD(x)	x*M_PI/180
#endif

/* boxes !! */
///scaling of the objects (0.1 = 20 centimeter boxes )
#define SCALING 1.
#define START_POS_X 46
#define START_POS_Y 1
#define START_POS_Z 150
///create 125 (5x5x5) dynamic object
#define ARRAY_SIZE_X 5
#define ARRAY_SIZE_Y 5
#define ARRAY_SIZE_Z 5

#define CUBE_HALF_EXTENTS 1

#define CLOTH_X 30
#define CLOTH_Y 10
#define CLOTH_NODES CLOTH_X*CLOTH_Y

int rightIndex = 0;
int upIndex = 1;
int forwardIndex = 2;

const int maxProxies = 32766;
const int maxOverlap = 65535;

btSoftBody* slingCloth;
int clothCenterNodeIndex;

btRigidBody* birdBody;

btRigidBody* groundBody;

btRigidBody* slingShotTrunk;
btRigidBody* slingShotLeftArm;
btRigidBody* slingShotRightArm;
btVector3 slingOrigin;
float slingScale;

btScalar slingAimY;

bool hold;	//controla se o bird deve ser 'segurado' na posição do estilingue, ou ja foi solto
//bool flying;
//bool stopped;
int flying;
int stopped;

////////////////////////////////////

AngryBr3ds::AngryBr3ds()
:
m_cameraHeight(4.f),
m_minCameraDistance(3.f),
m_maxCameraDistance(10.f),
m_drag(false),
m_node(0)
{
	m_cameraPosition = btVector3(0,0,0);
	m_useDefaultCamera = false;
	hold = true;
	stopped = false;
	setTexturing(true);
	setShadows(true);
	points = 0;
	birdsShot = 0;
	multiplier = 10;
}

void AngryBr3ds::termPhysics()
{
	//cleanup in the reverse order of creation/initialization
	//remove the rigidbodies from the dynamics world and delete them
	int i;
	for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
	{
		btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
		btRigidBody* body = btRigidBody::upcast(obj);
		if (body && body->getMotionState())
		{

			while (body->getNumConstraintRefs())
			{
				btTypedConstraint* constraint = body->getConstraintRef(0);
				m_dynamicsWorld->removeConstraint(constraint);
				delete constraint;
			}
			delete body->getMotionState();
			m_dynamicsWorld->removeRigidBody(body);
		} else
		{
			m_dynamicsWorld->removeCollisionObject( obj );
		}
		delete obj;
	}

	for (int j=0;j<m_collisionShapes.size();j++)
	{
		btCollisionShape* shape = m_collisionShapes[j];
		delete shape;
	}

	delete m_dynamicsWorld;
	delete m_constraintSolver;
	delete m_overlappingPairCache;
	delete m_dispatcher;
	delete m_collisionConfiguration;
}

AngryBr3ds::~AngryBr3ds()
{
	termPhysics();
}

void pickingPreTickCallback (btDynamicsWorld *world, btScalar timeStep)
{
       	AngryBr3ds* angry = (AngryBr3ds*)world->getWorldUserInfo();

        if(angry->m_drag)
        {
                const int                       x=angry->m_lastmousepos[0];
                const int                       y=angry->m_lastmousepos[1];
                const btVector3                 rayFrom=angry->getCameraPosition();
                const btVector3                 rayTo=angry->getRayTo(x,y);
                const btVector3                 rayDir=(rayTo-rayFrom).normalized();
                const btVector3                 N=(angry->getCameraTargetPosition()-angry->getCameraPosition()).normalized();
                const btScalar                  O=btDot(angry->m_impact,N);
                const btScalar                  den=btDot(N,rayDir);
                if((den*den)>0)
                {
                        const btScalar                  num=O-btDot(N,rayFrom);
                        const btScalar                  hit=num/den;
                        if((hit>0)&&(hit<1500))
                        {
                                angry->m_goal=rayFrom+rayDir*hit;
                        }
                }
                btVector3                               delta=angry->m_goal-angry->m_node->m_x;
                static const btScalar   maxdrag=50;
                if(delta.length2()>(maxdrag*maxdrag))
                {
                        delta=delta.normalized()*maxdrag;
                }
		delta.setZ(delta.y());
		delta.setY(0);
                angry->m_node->m_v+=delta/timeStep;
        }
}

void AngryBr3ds::createSlingshot(float scale, btVector3 &origin){
	btVector3 slingshotShapeSize = btVector3(0.2f, 2.f, 0.2f)*scale;
	btCollisionShape* slingshotShapeI = new btBoxShape(slingshotShapeSize);
	m_collisionShapes.push_back(slingshotShapeI);
	btTransform tr_slingshotI;
	tr_slingshotI.setIdentity();
	tr_slingshotI.setOrigin(origin);
	int* temp1 = new int;
	*temp1 = 333333333;
	slingshotShapeI->setUserPointer(temp1);
	slingShotTrunk = localCreateRigidBody(0,tr_slingshotI,slingshotShapeI);

	btCollisionShape* slingshotShapeV1 = new btBoxShape(btVector3(0.2f, 1.f, 0.2f)*scale);
	m_collisionShapes.push_back(slingshotShapeV1);
	btTransform tr_slingshotV1;
	tr_slingshotV1.setIdentity();
	tr_slingshotV1.setRotation(btQuaternion(btVector3(0,0,1),DEGTORAD(-30)));
	origin.setX(origin.x()+0.6f*scale);
	origin.setY(origin.y()+2.5*scale);
	tr_slingshotV1.setOrigin(origin);
	int* temp2 = new int;
	*temp2 = 333333333;
	slingshotShapeV1->setUserPointer(temp2);
	slingShotLeftArm = localCreateRigidBody(0,tr_slingshotV1,slingshotShapeV1);
		
	btCollisionShape* slingshotShapeV2 = new btBoxShape(btVector3(0.2f, 1.f, 0.2f)*scale);
	m_collisionShapes.push_back(slingshotShapeV2);
	btTransform tr_slingshotV2;
	tr_slingshotV2.setIdentity();
	tr_slingshotV2.setRotation(btQuaternion(btVector3(0,0,1),DEGTORAD(30)));
	origin.setX(origin.x()-(0.6f*scale*2));
	tr_slingshotV2.setOrigin(origin);
	int* temp3 = new int;
	*temp3 = 333333333;
	slingshotShapeV2->setUserPointer(temp3);
	slingShotRightArm = localCreateRigidBody(0,tr_slingshotV2,slingshotShapeV2);

	origin.setX(origin.x()+0.6f*scale);

	btVector3 downRight(origin.x()-1*scale, origin.y()+0.3f*scale, origin.z()+0.2f*scale);
	btVector3 downLeft(origin.x()+1*scale, origin.y()+0.3f*scale, origin.z()+0.2f*scale);
	btVector3 upRight(origin.x()-1*scale, origin.y()+1.0f*scale, origin.z()+0.2f*scale);
	btVector3 upLeft(origin.x()+1*scale, origin.y()+1.0f*scale, origin.z()+0.2f*scale);
	
        slingCloth=btSoftBodyHelpers::CreatePatch(m_softBodyWorldInfo, downRight, downLeft, upRight, upLeft, CLOTH_X,CLOTH_Y, 1+2+4+8,true);
	clothCenterNodeIndex = (CLOTH_X*(CLOTH_Y/2))+CLOTH_X/2-1;
        btSoftBody::Material* slingClothMat=slingCloth->appendMaterial();
        slingCloth->generateBendingConstraints(2, slingClothMat);
        slingCloth->setTotalMass(100*scale);
        getSoftDynamicsWorld()->addSoftBody(slingCloth);
}

void AngryBr3ds::createNewBird(float scale){
	btTransform startTransform;
	btVector3 localInertia(0,0,0);

	btScalar	massbird(5.*scale);
	btCollisionShape* birdShape = new btSphereShape(0.25*scale);
	m_collisionShapes.push_back(birdShape);
	birdShape->calculateLocalInertia(massbird,localInertia);
	int* temp = new int;
	*temp = 444444444;
	birdShape->setUserPointer(temp);
	startTransform.setIdentity();
	//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
	btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
	btRigidBody::btRigidBodyConstructionInfo rbInfo(massbird,myMotionState,birdShape,localInertia);
	birdBody = new btRigidBody(rbInfo);
	birdBody->setActivationState(DISABLE_DEACTIVATION);
	birdBody->setFriction(1.f);
	birdBody->setDamping(0.4f, 0.4f);

	birdBody->setContactProcessingThreshold(1e30);
        ///when using m_ccdMode, disable regular CCD
	birdBody->setCcdMotionThreshold(0.0001);
        birdBody->setCcdSweptSphereRadius(0.4f);

	m_dynamicsWorld->addRigidBody(birdBody);
}

btRigidBody* AngryBr3ds::createNewBrick(btVector3 &pos, btVector3 &size, btScalar &mass, btVector3 &localInertia){
	btCollisionShape* brickShape = new btBoxShape(size);
	m_collisionShapes.push_back(brickShape);	
	brickShape->calculateLocalInertia(mass, localInertia);
	btTransform trBrick;
	trBrick.setIdentity();
	trBrick.setOrigin(pos);
	btDefaultMotionState* brickMotionState = new btDefaultMotionState(trBrick);
	btRigidBody::btRigidBodyConstructionInfo brickInfo(mass,brickMotionState,brickShape,localInertia);
	btRigidBody* brickBody = new btRigidBody(brickInfo);
	brickBody->setCcdMotionThreshold(1e-7);
	int* temp = new int;
	*temp = 222222222;
	brickShape->setUserPointer(temp);
	return brickBody;
}

btRigidBody* AngryBr3ds::createNewPig(btVector3 &pos, btVector3 &size, btScalar &mass, btVector3 &localInertia){
	btCollisionShape* brickShape = new btCapsuleShape(1.5f, 1.5f);
	m_collisionShapes.push_back(brickShape);	
	int* temp = new int;
	*temp = 555555555;
	brickShape->setUserPointer(temp);
	brickShape->calculateLocalInertia(mass, localInertia);
	btTransform trBrick;
	trBrick.setIdentity();
	trBrick.setOrigin(pos);
	btDefaultMotionState* brickMotionState = new btDefaultMotionState(trBrick);
	btRigidBody::btRigidBodyConstructionInfo brickInfo(mass,brickMotionState,brickShape,localInertia);
	btRigidBody* brickBody = new btRigidBody(brickInfo);
	brickBody->setCcdMotionThreshold(1e-7);
	return brickBody;
}

void AngryBr3ds::setLevel(){
	{
		btVector3 pos1(40.f, 1.f, 50.f);
		btVector3 size1(1.f, 5.f, 1.f);
		btScalar mass1 = 5.f;
		btVector3 localInertia1(0.f, 0.f ,0.f);
		btRigidBody* body1 = createNewBrick(pos1, size1, mass1, localInertia1);	
		Brick brick1;
		brick1.body = body1;
		brick1.mass = mass1;
		brick1.hitGround = true;
		brick1.hitBird = true;
		bricks.push_back(brick1);
		m_dynamicsWorld->addRigidBody(body1);
	}
	{	
		btVector3 pos2(60.f, 1.f, 50.f);
		btVector3 size2(1.f, 5.f, 1.f);
		btScalar mass2 = 5.f;
		btVector3 localInertia2(0.f, 0.f ,0.f);
		btRigidBody* body2 = createNewBrick(pos2, size2, mass2, localInertia2);
		Brick brick2;
		brick2.body = body2;
		brick2.mass = mass2;
		brick2.hitGround = true;
		brick2.hitBird = true;
		bricks.push_back(brick2);
		m_dynamicsWorld->addRigidBody(body2);
	}
	{	
		btVector3 pos3(40.f, 1.f, 70.f);
		btVector3 size3(1.f, 5.f, 1.f);
		btScalar mass3 = 5.f;
		btVector3 localInertia3(0.f, 0.f ,0.f);
		btRigidBody* body3 = createNewBrick(pos3, size3, mass3, localInertia3);
		Brick brick3;
		brick3.body = body3;
		brick3.mass = mass3;
		brick3.hitGround = true;
		brick3.hitBird = true;
		bricks.push_back(brick3);
		m_dynamicsWorld->addRigidBody(body3);
	}
	{	
		btVector3 pos4(60.f, 1.f, 70.f);
		btVector3 size4(1.f, 5.f, 1.f);
		btScalar mass4 = 5.f;
		btVector3 localInertia4(0.f, 0.f ,0.f);
		btRigidBody* body4 = createNewBrick(pos4, size4, mass4, localInertia4);
		Brick brick4;
		brick4.body = body4;
		brick4.mass = mass4;
		brick4.hitGround = true;
		brick4.hitBird = true;
		bricks.push_back(brick4);
		m_dynamicsWorld->addRigidBody(body4);
	}
	{	
		btVector3 pos5(50.f, 6.f, 60.f);
		btVector3 size5(12.5f, 1.f, 12.5f);
		btScalar mass5 = 25.f;
		btVector3 localInertia5(0.f, 0.f ,0.f);
		btRigidBody* body5 = createNewBrick(pos5, size5, mass5, localInertia5);
		Brick brick5;
		brick5.body = body5;
		brick5.mass = mass5;
		brick5.hitGround = true;
		brick5.hitBird = true;
		bricks.push_back(brick5);
		m_dynamicsWorld->addRigidBody(body5);
	}
	{	
		btVector3 pos5(45.f, 7.f, 55.f);
		btVector3 size5(1.f, 5.f, 1.f);
		btScalar mass5 = 5.f;
		btVector3 localInertia5(0.f, 0.f ,0.f);
		btRigidBody* body5 = createNewBrick(pos5, size5, mass5, localInertia5);
		Brick brick5;
		brick5.body = body5;
		brick5.mass = mass5;
		brick5.hitGround = true;
		brick5.hitBird = true;
		bricks.push_back(brick5);
		m_dynamicsWorld->addRigidBody(body5);
	}
	{	
		btVector3 pos5(55.f, 7.f, 55.f);
		btVector3 size5(1.f, 5.f, 1.f);
		btScalar mass5 = 5.f;
		btVector3 localInertia5(0.f, 0.f ,0.f);
		btRigidBody* body5 = createNewBrick(pos5, size5, mass5, localInertia5);
		Brick brick5;
		brick5.body = body5;
		brick5.mass = mass5;
		brick5.hitGround = true;
		brick5.hitBird = true;
		bricks.push_back(brick5);
		m_dynamicsWorld->addRigidBody(body5);
	}
	{	
		btVector3 pos5(45.f, 7.f, 65.f);
		btVector3 size5(1.f, 5.f, 1.f);
		btScalar mass5 = 5.f;
		btVector3 localInertia5(0.f, 0.f ,0.f);
		btRigidBody* body5 = createNewBrick(pos5, size5, mass5, localInertia5);
		Brick brick5;
		brick5.body = body5;
		brick5.mass = mass5;
		brick5.hitGround = true;
		brick5.hitBird = true;
		bricks.push_back(brick5);
		m_dynamicsWorld->addRigidBody(body5);
	}
	{	
		btVector3 pos5(55.f, 7.f, 65.f);
		btVector3 size5(1.f, 5.f, 1.f);
		btScalar mass5 = 5.f;
		btVector3 localInertia5(0.f, 0.f ,0.f);
		btRigidBody* body5 = createNewBrick(pos5, size5, mass5, localInertia5);
		Brick brick5;
		brick5.body = body5;
		brick5.mass = mass5;
		brick5.hitGround = true;
		brick5.hitBird = true;
		bricks.push_back(brick5);
		m_dynamicsWorld->addRigidBody(body5);
	}
	{	
		btVector3 pos5(50.f, 10.f, 60.f);
		btVector3 size5(7.5f, 1.f, 7.5f);
		btScalar mass5 = 5.f;
		btVector3 localInertia5(0.f, 0.f ,0.f);
		btRigidBody* body5 = createNewBrick(pos5, size5, mass5, localInertia5);
		Brick brick5;
		brick5.body = body5;
		brick5.mass = mass5;
		brick5.hitGround = true;
		brick5.hitBird = true;
		bricks.push_back(brick5);
		m_dynamicsWorld->addRigidBody(body5);
	}
	{	
		btVector3 pos5(50.f, 8.f, 60.f);
		btVector3 size5(2.f, 2.f, 2.f);
		btScalar mass5 = 30.f;
		btVector3 localInertia5(0.f, 0.f ,0.f);
		btRigidBody* body5 = createNewPig(pos5, size5, mass5, localInertia5);
		Brick brick5;
		brick5.body = body5;
		brick5.mass = mass5;
		brick5.hitGround = true;
		brick5.hitBird = true;
		bricks.push_back(brick5);
		body5->setDamping(0.5f, 0.5f);
		m_dynamicsWorld->addRigidBody(body5);
	}
}

void AngryBr3ds::initPhysics()
{
	m_debugMode |= btIDebugDraw::DBG_NoHelpText;

	cam.setInitialCamera();

	btVector3 worldMin(-1000,-1000,-1000);
        btVector3 worldMax(1000,1000,1000);

	m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration();
	m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
	m_overlappingPairCache = new btAxisSweep3(worldMin,worldMax);
	m_constraintSolver = new btSequentialImpulseConstraintSolver();

	btDiscreteDynamicsWorld* world = new btSoftRigidDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
        m_dynamicsWorld = world;
	m_dynamicsWorld->setInternalTickCallback(pickingPreTickCallback,this,true);

	m_dynamicsWorld->setGravity(btVector3(0, -10, 0));

	m_dynamicsWorld->getSolverInfo().m_splitImpulse=true;
	m_dynamicsWorld->getSolverInfo().m_numIterations=20;

	m_dynamicsWorld->getDispatchInfo().m_useContinuous=true;

	m_softBodyWorldInfo.m_sparsesdf.Initialize();
 	m_softBodyWorldInfo.air_density =	(btScalar)1.2;
        m_softBodyWorldInfo.water_density =	0;
        m_softBodyWorldInfo.water_offset =	0;
        m_softBodyWorldInfo.water_normal =	btVector3(0,0,0);
        m_softBodyWorldInfo.m_gravity.setValue(0,-10,0);
	m_softBodyWorldInfo.m_dispatcher = m_dispatcher;
	m_softBodyWorldInfo.m_broadphase = m_overlappingPairCache;

//-----------------create ground
//	btCollisionShape* groundShape = new btBoxShape(btVector3(50,1,100)); //half size =]
	btCollisionShape* groundShape = new btBox2dShape(btVector3(500,1,500)); //half size =]
	m_collisionShapes.push_back(groundShape);
	btTransform tr;
	tr.setIdentity();
	tr.setOrigin(btVector3(50,-1,100));	//para poder desenhar na origem como se fosse um plano cartesiano
	int* temp = new int;
	*temp = 111111111;
	groundShape->setUserPointer(temp);	
	groundBody = localCreateRigidBody(0,tr,groundShape);
//	groundBody->setFriction(1.0f);
//------------------------------

	slingScale = 2.f;
	slingOrigin = btVector3(50, 0, 10);
	createSlingshot(slingScale, slingOrigin);
	createNewBird(slingScale);

	setLevel();

		/* boxes !! */
	/*	{	
		//create a few dynamic rigidbodies
		// Re-using the same collision is better for memory usage and performance

		btCollisionShape* colShape = new btBoxShape(btVector3(SCALING*1,SCALING*1,SCALING*1));
		//btCollisionShape* colShape = new btSphereShape(btScalar(1.));
		m_collisionShapes.push_back(colShape);

		/// Create Dynamic Objects
		btTransform startTransform;
		startTransform.setIdentity();

		btScalar	mass(1.f);

		//rigidbody is dynamic if and only if mass is non zero, otherwise static
		bool isDynamic = (mass != 0.f);

		btVector3 localInertia(0,0,0);
		if (isDynamic)
			colShape->calculateLocalInertia(mass,localInertia);

		float start_x = START_POS_X;// - ARRAY_SIZE_X/2;
		float start_y = START_POS_Y;
		float start_z = START_POS_Z;// - ARRAY_SIZE_Z/2;

		for (int k=0;k<ARRAY_SIZE_Y;k++)
		{
			for (int i=0;i<ARRAY_SIZE_X;i++)
			{
				for(int j = 0;j<ARRAY_SIZE_Z;j++)
				{	
					startTransform.setOrigin(SCALING*btVector3(
										btScalar(2.0*i + start_x),
										btScalar(2.0*k + start_y),
										btScalar(2.0*j + start_z)));
					//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
					btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
					btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia);
					btRigidBody* body = new btRigidBody(rbInfo);
					m_dynamicsWorld->addRigidBody(body);
				}
			}
		}
	}*/
	clientResetScene();
	//setCameraDistance(26.f);
}

void AngryBr3ds::writeScreenInfo(){
	int lineWidth=250;
	int xStart = 0;//m_glutScreenWidth - lineWidth;
	int yStart = 20;
	setOrthographicProjection();
	glDisable(GL_LIGHTING);
	btVector3 textColor(1.0f, 1.0f, 0.0f);
	char buf[124];
	
	glRasterPos3f(xStart, yStart, 0);
	switch (cam.activeCamera){
		default:
		case 0: 
			sprintf(buf,"Camera: Follow that Bird!");
			break;
		case 1:
			sprintf(buf,"Camera: Helicopter");
			break;
		case 2:
			sprintf(buf,"Camera: Free mode");
			break;
	}
	GLDebugDrawString(xStart,20,buf,textColor);
//	yStart+=20;
	glRasterPos3f(xStart, yStart, 0);
	sprintf(buf,"Slingshot Angle: %0.0lf", slingAimY);
	yStart+=20;
	GLDebugDrawString(xStart,yStart,buf,textColor);
	glRasterPos3f(xStart, yStart, 0);
	sprintf(buf,"Birds shot: %d", birdsShot);
	yStart+=20;
	GLDebugDrawString(xStart,yStart,buf);
	glRasterPos3f(xStart, yStart, 0);
        sprintf(buf,"Score: %d", points);
	yStart+=20;
	GLDebugDrawString(xStart,yStart,buf);

	resetPerspectiveProjection();
	glEnable(GL_LIGHTING);
}

void AngryBr3ds::renderme()
{
	updateCamera();

	btVector3	worldBoundsMin,worldBoundsMax;
	getDynamicsWorld()->getBroadphase()->getBroadphaseAabb(worldBoundsMin,worldBoundsMax);

	//--------DRAW SOFT BODIES
	btSoftRigidDynamicsWorld* softWorld = (btSoftRigidDynamicsWorld*)m_dynamicsWorld;
        for (  int i=0;i<softWorld->getSoftBodyArray().size();i++)
        {
                btSoftBody*     psb=(btSoftBody*)softWorld->getSoftBodyArray()[i];
                if (softWorld->getDebugDrawer() && !softWorld->getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe))
                {
                        btSoftBodyHelpers::DrawFrame(psb,softWorld->getDebugDrawer());
                        btSoftBodyHelpers::Draw(psb,softWorld->getDebugDrawer(),softWorld->getDrawFlags());
                }
        }

        /* Bodies               */
        btVector3 ps(0,0,0);
        int nps=0;
        btSoftBodyArray& sbs=softWorld->getSoftBodyArray();
        for(int ib=0;ib<sbs.size();++ib)
        {
                btSoftBody*     psb=sbs[ib];
                nps+=psb->m_nodes.size();
                for(int i=0;i<psb->m_nodes.size();++i)
                {
                        ps+=psb->m_nodes[i].m_x;
                }
        }
	//-----------END SOFT BODIES
	
	writeScreenInfo();
	
	DemoApplication::renderme();
}

void AngryBr3ds::clientMoveAndDisplay()
{

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 


	for (int i = 0; i < bricks.size(); i++){
		if (bricks[i].body->getActivationState() == 2){
			bricks[i].hitGround = false;
			bricks[i].hitBird = false;
		}
		else if (bricks[i].mass < 0.f){
			m_dynamicsWorld->removeCollisionObject(static_cast<btCollisionObject*>(bricks[i].body));
		}
	}

	if (hold){
		if (!birdBody){
			slingAimY = slingCloth->m_nodes[clothCenterNodeIndex].m_x.y();
			createNewBird(slingScale);				
		}
		flying = 0;
		stopped = 0;
		btTransform birdNewPos;
		birdNewPos.setIdentity();;
		birdNewPos.setOrigin(btVector3(slingCloth->m_nodes[clothCenterNodeIndex].m_x.x(), slingCloth->m_nodes[clothCenterNodeIndex].m_x.y(), slingCloth->m_nodes[clothCenterNodeIndex].m_x.z()+.5f*slingScale));
		birdBody->setCenterOfMassTransform(birdNewPos);
		birdBody->setLinearVelocity(btVector3(0,0,0));
		birdBody->setAngularVelocity(btVector3(0,0,0));
	}

	if (flying){
		if (birdBody->getLinearVelocity().z() < 1){
			birdBody->applyDamping(0.5);
		}
		if (birdBody->getLinearVelocity().z() < 0.1){
			stopped = 1;
		}		
	}

	float dt = getDeltaTimeMicroseconds() * 0.000001f;
	printf("%lf\n", dt);
	if (m_dynamicsWorld)
	{
		//during idle mode, just run 1 simulation step maximum
		int maxSimSubSteps = m_idle ? 1 : 10;
		if (m_idle)
			dt = 1.0/420.f;
		int numSimSteps = m_dynamicsWorld->stepSimulation(dt,maxSimSubSteps);

//#define VERBOSE_FEEDBACK
#ifdef VERBOSE_FEEDBACK
		if (!numSimSteps){
			printf("Interpolated transforms\n");
		}
		else
		{
			if (numSimSteps > maxSimSubSteps)
			{
				//detect dropping frames
				printf("Dropped (%i) simulation steps out of %i\n",numSimSteps - maxSimSubSteps,numSimSteps);
			} else
			{
				printf("Simulated (%i) steps\n",numSimSteps);
			}
		}
#endif //VERBOSE_FEEDBACK
	}
	
//	int numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds();
	for (int i=0;i<m_dynamicsWorld->getDispatcher()->getNumManifolds();i++)
	{
		btPersistentManifold* contactManifold =  m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
//		btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
//		btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
		for (int j=0;j<contactManifold->getNumContacts();j++)
		{
			btManifoldPoint& pt = contactManifold->getContactPoint(j);
			if (contactManifold->getContactPoint(j).getDistance()!=0.f)
			{
//				const btVector3& ptA = pt.getPositionWorldOnA();
//				const btVector3& ptB = pt.getPositionWorldOnB();
				btRigidBody* riA = static_cast<btRigidBody*>(contactManifold->getBody0());
				btRigidBody* riB = static_cast<btRigidBody*>(contactManifold->getBody1());
				if (riA == groundBody || riB == groundBody){	//colisao com ground, nao interessa, nao faz nada, obvsly
					for (int i = 0; i < bricks.size(); i++){
						if (riB == bricks[i].body){
							if (!bricks[i].hitGround && pt.m_appliedImpulse > 10.f){
								bricks[i].mass -= pt.m_appliedImpulse/7.f;
								points += (int)pt.m_appliedImpulse/5 * multiplier; 
								bricks[i].hitGround = true;
								if (bricks[i].mass < 0.f){
									m_dynamicsWorld->removeCollisionObject(static_cast<btCollisionObject*>(riB));
									for (int i = 0; i < bricks.size(); i++){
										bricks[i].body->setActivationState(1);
									}
								}
							}
						}
						else{
							continue;
						}
					}
				}
				else if ((riA == slingShotTrunk || riB == slingShotTrunk) 
					|| (riA == slingShotLeftArm || riB == slingShotLeftArm)
					|| (riA == slingShotRightArm || riB == slingShotRightArm)){	//colisao com slingshot desabilitada
					continue;
				}
				else if (birdBody == riB){					
					continue;
				}
				else if (birdBody == riA){	//A ou B, depende da ordem de criação do body, em relação a ordem do outro body. 
				//ex: bird antes de bloco, bird = A, bloco = B, sempre						
					for (int i = 0; i < bricks.size(); i++){
						if (riB == bricks[i].body){
							if (!bricks[i].hitBird){
								btVector3 tempnormal = pt.m_normalWorldOnB;
								btScalar impactForce = pt.getAppliedImpulse();
								bricks[i].mass -= impactForce;
								points += (int)impactForce * multiplier;
								bricks[i].hitBird = true;
								if (bricks[i].mass < 0.f){									
									m_dynamicsWorld->removeCollisionObject(static_cast<btCollisionObject*>(riB));
									bricks[i].body->setLinearVelocity(bricks[i].body->getLinearVelocity()*0.25);
									for (int i = 0; i < bricks.size(); i++){
										bricks[i].body->setActivationState(1);
									}
								}
							}														
						}
					}
				}
				else{
					for (int i = 0; i < bricks.size()/2; i++){
						if (bricks[i].body == riA){
							for (int j = 0; j < bricks.size(); j++){
								if (bricks[i].body != bricks[j].body){
									if (!bricks[i].hitGround && pt.m_appliedImpulse > 10.f){
										bricks[i].mass -= pt.m_appliedImpulse/7.f;
										points += (int)pt.m_appliedImpulse/5 * multiplier;
										bricks[i].hitGround = true;
										bricks[j].mass -= pt.m_appliedImpulse/7.f;
										points += (int)pt.m_appliedImpulse/5 * multiplier;
										bricks[j].hitGround = true;
										if (bricks[i].mass < 0.f){
											m_dynamicsWorld->removeCollisionObject(static_cast<btCollisionObject*>(riA));
											for (int i = 0; i < bricks.size(); i++){
												bricks[i].body->setActivationState(1);
											}
										}
										if (bricks[j].mass < 0.f){
											m_dynamicsWorld->removeCollisionObject(static_cast<btCollisionObject*>(riB));
											for (int i = 0; i < bricks.size(); i++){
												bricks[i].body->setActivationState(1);
											}
										}
									}
								}
							}
						}
						else if (bricks[i].body == riB){
							for (int j = 0; j < bricks.size(); j++){
								if (bricks[i].body != bricks[j].body){
									if (!bricks[i].hitGround && pt.m_appliedImpulse > 10.f){
										bricks[i].mass -= pt.m_appliedImpulse/7.f;
										points += (int)pt.m_appliedImpulse/5 * multiplier;
										bricks[i].hitGround = true;
										bricks[j].mass -= pt.m_appliedImpulse/7.f;
										points += (int)pt.m_appliedImpulse/5 * multiplier;
										bricks[j].hitGround = true;
										if (bricks[i].mass < 0.f){
											m_dynamicsWorld->removeCollisionObject(static_cast<btCollisionObject*>(riB));
											for (int i = 0; i < bricks.size(); i++){
												bricks[i].body->setActivationState(1);
											}
										}
										if (bricks[j].mass < 0.f){
											m_dynamicsWorld->removeCollisionObject(static_cast<btCollisionObject*>(riA));
											for (int i = 0; i < bricks.size(); i++){
												bricks[i].body->setActivationState(1);
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}


#ifdef USE_QUICKPROF 
        btProfiler::beginBlock("render"); 
#endif //USE_QUICKPROF 

	renderme(); 

	//optional but useful: debug drawing
//	if (m_dynamicsWorld)
		//m_dynamicsWorld->debugDrawWorld();

#ifdef USE_QUICKPROF 
        btProfiler::endBlock("render"); 
#endif 

        if(m_drag)//necessario para click e drag em softbodies
        {
        	m_node->m_v*=0;
        }
        m_softBodyWorldInfo.m_sparsesdf.GarbageCollect();//parece bom


	glFlush();
	glutSwapBuffers();
}


void AngryBr3ds::displayCallback(void) 
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

	renderme();

//optional but useful: debug drawing
//	if (m_dynamicsWorld)
//		m_dynamicsWorld->debugDrawWorld();

	glFlush();
	glutSwapBuffers();
}



void AngryBr3ds::clientResetScene()
{
}

void AngryBr3ds::specialKeyboardUp(int key, int x, int y)
{
   switch (key) 
	{
	case GLUT_KEY_UP :
		{
			break;
		}
	case GLUT_KEY_DOWN :
		{
			break;
		}
	case GLUT_KEY_LEFT:
	case GLUT_KEY_RIGHT:
		{
			break;
		}
	default:
		DemoApplication::specialKeyboardUp(key,x,y);
		break;
	}
}


void AngryBr3ds::specialKeyboard(int key, int x, int y)
{

	int state;
	state=glutGetModifiers();
	if (state & GLUT_ACTIVE_SHIFT) 
	{
		switch (key) 
			{
			case GLUT_KEY_LEFT : 
				{
					if (cam.activeCamera == 2)
						cam.lookLeft();
					break;
				}
			case GLUT_KEY_RIGHT : 
				{
					if (cam.activeCamera == 2)
						cam.lookRight();
					break;
				}
			case GLUT_KEY_UP :
				{
					if (cam.activeCamera == 2)
						cam.lookUp();
					break;
				}
			case GLUT_KEY_DOWN :
				{
					if (cam.activeCamera == 2)
						cam.lookDown();
					break;
				}

			default:
				DemoApplication::specialKeyboard(key,x,y);
				break;
			}
	} else
	{
			switch (key) 
			{
			case GLUT_KEY_F8:
			{
				birdBody->applyCentralImpulse(btVector3(0,0,10));
				break;
			}
			case GLUT_KEY_F6:
			{
				if (multiplier == 10){
					multiplier = 20;
				}
				else{
					multiplier = 10;
				}
				break;
			}
			case GLUT_KEY_HOME:
				{	
				
					if (cam.activeCamera == 2)
						cam.moveUp();
					else if (cam.activeCamera == 1)
						cam.heliZoomIn();
					break;
				}
			case GLUT_KEY_END:
				{		
					if (cam.activeCamera == 2)
						cam.moveDown();
					else if (cam.activeCamera == 1)
						cam.heliZoomOut();
					break;
				}
			case GLUT_KEY_LEFT : 
				{
					if (cam.activeCamera == 2)
						cam.strafeLeft();
					else if (cam.activeCamera == 1)
						cam.heliLeft();
					break;
				}
			case GLUT_KEY_RIGHT : 
				{
					if (cam.activeCamera == 2)
						cam.strafeRight();
					else if (cam.activeCamera == 1)
						cam.heliRight();
					break;
				}
			case GLUT_KEY_UP :
				{
					if (cam.activeCamera == 2)
						cam.moveForward();
					else if (cam.activeCamera == 1)
						cam.heliForward();
					break;
				}
			case GLUT_KEY_DOWN :
				{
					if (cam.activeCamera == 2)
						cam.moveBackward();
					else if (cam.activeCamera == 1)
						cam.heliBackward();
					break;
				}
			case GLUT_KEY_F1:
				{
					cam.activeCamera = 0;	// bird
					break;
				}
			case GLUT_KEY_F2:
				{
					cam.activeCamera = 1;	// heli
					break;
				}
			case GLUT_KEY_F3:
				{
					cam.activeCamera = 2;	// free
					break;
				}			
			case GLUT_KEY_F5:
				//m_useDefaultCamera = !m_useDefaultCamera;
				break;
			default:
				DemoApplication::specialKeyboard(key,x,y);
				break;
			}
	}
}

void AngryBr3ds::mouseMotionFunc(int x,int y)
{
        if(m_node&&(m_results.fraction<1.f))
        {
                if(!m_drag)
                {
#define SQ(_x_) (_x_)*(_x_)
                        if((SQ(x-m_lastmousepos[0])+SQ(y-m_lastmousepos[1]))>6)
                        {
                                m_drag=true;
                        }
#undef SQ
                }
                if(m_drag)
                {
                        m_lastmousepos[0]       =       x;
                        m_lastmousepos[1]       =       y;
                }
        }
        else
        {
                DemoApplication::mouseMotionFunc(x,y);
        }
}


void AngryBr3ds::mouseFunc(int button, int state, int x, int y)
{
        if(button==0)
        {
                switch(state)
                {
                case    0:
                        {
                                m_results.fraction=1.f;
                                DemoApplication::mouseFunc(button,state,x,y);
                                if(!m_pickConstraint)
                                {
                                        const btVector3                 rayFrom=m_cameraPosition;
                                        const btVector3                 rayTo=getRayTo(x,y);
                                        const btVector3                 rayDir=(rayTo-rayFrom).normalized();
                                        btSoftBodyArray&                sbs=getSoftDynamicsWorld()->getSoftBodyArray();
                                        for(int ib=0;ib<sbs.size();++ib)
                                        {
                                                btSoftBody*                             psb=sbs[ib];
                                                btSoftBody::sRayCast    res;
                                                if(psb->rayTest(rayFrom,rayTo,res))	//encontra valores que definem o impacto do vetor rayTo-rayFrom
						//length de rayto ateh rayfrom eh todo espaço visivel da camera ateh o ponto clicado, dentro do mundo.
                                                {
                                                        m_results=res;
							hold = true;
                                                }
                                        }
                                        if(m_results.fraction<1.f)
                                        {
						//printf("ray from %lf %lf %lf\n", rayFrom.x(), rayFrom.y(), rayFrom.z());
						//printf("ray to %lf %lf %lf\n", rayTo.x(), rayTo.y(), rayTo.z());
						//printf("ray dir %lf %lf %lf\n", rayDir.x(), rayDir.y(), rayDir.z());
                                                m_impact                        =       rayFrom+(rayTo-rayFrom)*m_results.fraction;
						//printf("impact %lf %lf %lf\n", m_impact.x(), m_impact.y(), m_impact.z());
						//rayFrom = posição da camera
						//rayTo = ? (ok, onde foi clicado no mundo, mas ql limite?)
						// ray dir = direção (orly?)
						// impact = posição no mundo que encontra o vetor (rayto-rayfrom) com o softbody (m_results)
                                                m_drag                          =       false;
                                                m_lastmousepos[0]       =       x;
                                                m_lastmousepos[1]       =       y;
                                                m_node                          =       0;
                                                switch(m_results.feature)
                                                {
                                                case    btSoftBody::eFeature::Face:
                                                        {
                                                                btSoftBody::Face&       f=m_results.body->m_faces[m_results.index];	//seleciona face clicada
                                                                m_node=f.m_n[0];
                                                                for(int i=1;i<3;++i)	//para cada nodo da face (triangle, por isso for de 3)
                                                                {
                                                                        if(     (m_node->m_x-m_impact).length2()>
                                                                                (f.m_n[i]->m_x-m_impact).length2())	
									// length do vetor de diff entre posição clicada e um dos 3 nodes da face clicada 
									// pega node (da face) que esta mais proximo do ponto clicado
                                                                        {
                                                                                m_node=f.m_n[i];
                                                                        }
                                                                }
                                                        }
                                                        break;
                                                }
                                                if(m_node) m_goal=m_node->m_x;
                                                return;
                                        }
                                }
                        }
                        break;
		case    1:
			/* achar alguma formula boa para velocidade
			aqui, eh calculada a partir do vetor normal do ponto no qual a bola esta ligada*/			
			if (hold){	
//				birdBody->setLinearFactor(btVector3(1,1,1));	// 'o quanto a gravidade age sobre o movimento do corpo'
//				birdBody->setLinearVelocity(btVector3((x-515)/10,slingAimY,(y-150)/15-slingAimY/3));
//				birdBody->applyCentralImpulse(btVector3((x-515),slingAimY*5,(y-150)-slingAimY));
				btVector3 birdpos = birdBody->getCenterOfMassPosition();
				btVector3 birdOrigin = btVector3(50, 0, 20); //posicao do slingshot + deslocamento do elastico
				birdBody->applyCentralImpulse(btVector3(-(birdpos.x()-birdOrigin.x())*250, slingAimY*6, -(birdpos.z()-birdOrigin.z())*(75-slingAimY)));
				hold = false;
				flying = 1;
				birdsShot++;
			}

                        m_results.fraction=1.f;
                        m_drag=false;
                        DemoApplication::mouseFunc(button,state,x,y);
                        break;
                }
        }
        else if (button==3){	//scroll up
		if (hold){
	//		m_node->m_x.setY(m_node->m_x.y()-1);
			slingAimY -= 0.5f;
		}	
	}
	else if (button==4){	//scroll down
		if (hold){
//			m_node->m_x.setY(m_node->m_x.y()+1);
			slingAimY += 0.5f;
		}	
	}
	else
        {
                DemoApplication::mouseFunc(button,state,x,y);
        }
}


void	AngryBr3ds::updateCamera()
{
	if(m_useDefaultCamera)
	{
		DemoApplication::updateCamera();
		return;
	}

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	if (cam.activeCamera == 0){		//birdCam
		cam.updateBirdBackCamera(birdBody, flying, stopped);	
	}

	//update OpenGL camera settings
	btScalar aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight;
	glFrustum (-aspect, aspect, -1.0, 1.0, 1.0, 1000.0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	m_cameraPosition = cam.getActiveCameraPos();
	m_cameraTargetPosition = cam.getActiveCameraLookAt();
	m_cameraUp = cam.getActiveCameraUp();
    	gluLookAt(m_cameraPosition.x(),m_cameraPosition.y(), m_cameraPosition.z(), m_cameraTargetPosition.x(), m_cameraTargetPosition.y(), m_cameraTargetPosition.z(), m_cameraUp.x(),m_cameraUp.y(),m_cameraUp.z());
}
